package com.hc.comm.base;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.mybatis.spring.SqlSessionTemplate;

import com.hc.comm.utils.Constant.DbTypes;
import com.hc.comm.utils.Constant.DbTypes.DbTypeEnum;
import com.hc.comm.utils.StringUtil;


/**
 * dao顶层接口实现类，如果要实现通用的增删改查，只需要继承该类
 * 
 * @author Ready
 */
public abstract class BaseDaoImpl implements IBaseDao {

	/**
	 * 写
	 */
	protected SqlSessionTemplate writeSqlSession;
	/**
	 * 读
	 */
	protected SqlSessionTemplate readSqlSession;
	/**
	 * 数据库类型
	 */
	protected String dbtype = DbTypeEnum.MYSQL.getValue();
	/**
	 * comment 主键名称
	 */

	protected String primaryKeyName;

	/**
	 * sequence的名称
	 */
	protected String sequenceName;

	/**
	 * model对应sqlmap的插入前缀
	 */
	protected String sqlmapInsertPrefix = "insert";

	/**
	 * model对应sqlmap的删除前缀
	 */
	protected String sqlmapDeletePrefix = "delete";

	/**
	 * model对应sqlmap的修改前缀
	 */
	protected String sqlmapUpdatePrefix = "update";

	protected String sqlmapUpdateBymapPrefix = "updateByMap";

	/**
	 * model对应sqlmap的查询列表数量的前缀
	 */
	protected String sqlmapGetModelListCountPrefix = "getModelListCount";

	/**
	 * model对应sqlmap的查询列表的前缀
	 */
	protected String sqlmapGetModelListPrefix = "getModelList";

	/**
	 * 获取sqlmap的namespace前缀
	 * 
	 * @return
	 */
	protected String getNamesapceToSqlmapPrefix() {
		if (StringUtil.isNotEmpty(this.getSqlmapNamespace())) {
			return this.getSqlmapNamespace() + ".";
		}
		return "";
	}

	/**
	 * 获取statement
	 * 
	 * @param stuff
	 * @return
	 */
	protected String getStatement(String stuff) {
		return getNamesapceToSqlmapPrefix() + stuff;
	}

	/**
	 * 根据sequence的名称获取sequence的值
	 * 
	 * @param sequenceName
	 * @return
	 */
	public int getSequenceValueBySequenceName(String sequenceName)
			throws Exception {
		if (StringUtil.isNotEmpty(sequenceName)) {
			return Integer.parseInt(this
					.getSqlSession(true)
					.selectOne("global.getSequenceValueBySequenceName",
							sequenceName).toString());
		}
		return 0;
	}

	/**
	 * 新增model
	 * 
	 * @param <T>
	 * @param model
	 *            需要添加的model,需集成Model类
	 * @return 新增以后的model
	 * @throws Exception
	 */
	public <T extends Model> T insertModel(T model) throws Exception {
		// 如果是oracle则主键的值从sequence中获取
		if (StringUtil.isNotEmpty(primaryKeyName)) {
			Field field = model.getClass().getDeclaredField(primaryKeyName);
			if (!field.isAccessible()) {
				field.setAccessible(true);
			}
			if (DbTypes.isOracle(dbtype)) {
				field.set(model, getSequenceValueBySequenceName(sequenceName));
			} else {
				field.set(model, null);
			}
		}
		this.getSqlSession().insert(
				getNamesapceToSqlmapPrefix() + sqlmapInsertPrefix, model);
		return model;
	}

	/**
	 * @Title: insert
	 * @Description: 批量插入
	 * @param @param models
	 * @param @throws Exception 设定文件
	 * @return void 返回类型
	 * @throws
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void insertBatch(List models) throws Exception {
		if (models != null) {
			List tempList = new ArrayList();
			int i = 1;
			for (Object object : models) {
				tempList.add(object);
				if (i++ % 100 == 0) {
					this.getSqlSession().insert(getStatement("insertBatch"),
							tempList);
					tempList.clear();
				}
			}
			if (!tempList.isEmpty()) {
				this.getSqlSession().insert(getStatement("insertBatch"), tempList);
			}
		}
	}

	/**
	 * 删除一个对象
	 * 
	 * @param paramMap
	 *            参数列表
	 * @return 返回影响的行数
	 * @throws Exception
	 */
	public int deleteModel(Object object) throws Exception {
		return this.getSqlSession().delete(
				getNamesapceToSqlmapPrefix() + sqlmapDeletePrefix, object);
	}

	/**
	 * 修改model
	 * 
	 * @param model
	 * @return 影响的行数
	 * @throws Exception
	 */
	public int updateModel(Object object) throws Exception {
		return this.getSqlSession().update(
				getNamesapceToSqlmapPrefix() + sqlmapUpdatePrefix, object);
	}

	/**
	 * 根据map更新数据
	 * 
	 * @param paramMap
	 * @return
	 * @throws Exception
	 */
	public int updateByMap(Map<Object, Object> paramMap) throws Exception {
		return this.getSqlSession().update(
				this.getStatement(sqlmapUpdateBymapPrefix), paramMap);
	}

	/**
	 * 获取符合条件的model的数量
	 * 
	 * @param paramMap
	 * @return
	 * @throws Exception
	 */
	public long getModelListCount(Map<Object, Object> paramMap)
			throws Exception {
		return Long.parseLong(this
				.getSqlSession(true)
				.selectOne(
						getNamesapceToSqlmapPrefix()
								+ sqlmapGetModelListCountPrefix, paramMap)
				.toString());
	}

	/**
	 * 获取model列表
	 * 
	 * @param <T>
	 * @param paramMap
	 *            查询参数列表
	 * @return 返回结果列表
	 * @throws Exception
	 */
	@SuppressWarnings("rawtypes")
	public List getModelList(Map<Object, Object> paramMap) throws Exception {
		return this.getSqlSession(true).selectList(
				getNamesapceToSqlmapPrefix() + sqlmapGetModelListPrefix,
				paramMap);

	}

	@SuppressWarnings("unchecked")
	@Override
	public <T extends Model> T getModelById(Object id) throws Exception {
		Map<Object, Object> paramMap = new HashMap<Object, Object>();
		paramMap.put(this.getPrimaryKeyName(), id);
		List<T> list = this.getModelList(paramMap);
		if (list.size() >= 1) {
			return list.get(0);
		}
		return null;
	};

	/**
	 * 数据库类型
	 * 
	 * @return
	 */
	public String getDbtype() {
		return dbtype;
	}

	/**
	 * 数据库类型
	 * 
	 * @param dbtype
	 */
	public void setDbtype(String dbtype) {
		this.dbtype = dbtype;
	}

	/**
	 * mapper的namespace
	 * 
	 * @return
	 */
	public abstract String getSqlmapNamespace();

	/**
	 * sequence的名称
	 * 
	 * @return
	 */
	public String getSequenceName() {
		return sequenceName;
	}

	/**
	 * sequence的名称
	 * 
	 * @param sequenceName
	 */
	public void setSequenceName(String sequenceName) {
		this.sequenceName = sequenceName;
	}

	/**
	 * model对应sqlmap的插入前缀
	 * 
	 * @return
	 */
	public String getSqlmapInsertPrefix() {
		return sqlmapInsertPrefix;
	}

	/**
	 * model对应sqlmap的插入前缀
	 * 
	 * @param sqlmapInsertPrefix
	 */
	public void setSqlmapInsertPrefix(String sqlmapInsertPrefix) {
		this.sqlmapInsertPrefix = sqlmapInsertPrefix;
	}

	/**
	 * model对应sqlmap的删除前缀
	 * 
	 * @return
	 */
	public String getSqlmapDeletePrefix() {
		return sqlmapDeletePrefix;
	}

	/**
	 * model对应sqlmap的删除前缀
	 * 
	 * @param sqlmapDeletePrefix
	 */
	public void setSqlmapDeletePrefix(String sqlmapDeletePrefix) {
		this.sqlmapDeletePrefix = sqlmapDeletePrefix;
	}

	/**
	 * model对应sqlmap的修改前缀
	 * 
	 * @return
	 */
	public String getSqlmapUpdatePrefix() {
		return sqlmapUpdatePrefix;
	}

	/**
	 * model对应sqlmap的修改前缀
	 * 
	 * @param sqlmapUpdatePrefix
	 */
	public void setSqlmapUpdatePrefix(String sqlmapUpdatePrefix) {
		this.sqlmapUpdatePrefix = sqlmapUpdatePrefix;
	}

	/**
	 * model对应sqlmap的查询列表数量的前缀
	 * 
	 * @return
	 */
	public String getSqlmapGetModelListCountPrefix() {
		return sqlmapGetModelListCountPrefix;
	}

	/**
	 * model对应sqlmap的查询列表数量的前缀
	 * 
	 * @param sqlmapGetModelListCountPrefix
	 */
	public void setSqlmapGetModelListCountPrefix(
			String sqlmapGetModelListCountPrefix) {
		this.sqlmapGetModelListCountPrefix = sqlmapGetModelListCountPrefix;
	}

	/**
	 * model对应sqlmap的查询列表的前缀
	 * 
	 * @return
	 */
	public String getSqlmapGetModelListPrefix() {
		return sqlmapGetModelListPrefix;
	}

	/**
	 * model对应sqlmap的查询列表的前缀
	 * 
	 * @param sqlmapGetModelListPrefix
	 */
	public void setSqlmapGetModelListPrefix(String sqlmapGetModelListPrefix) {
		this.sqlmapGetModelListPrefix = sqlmapGetModelListPrefix;
	}

	public String getPrimaryKeyName() {
		return primaryKeyName;
	}

	public void setPrimaryKeyName(String primaryKeyName) {
		this.primaryKeyName = primaryKeyName;
	}

	public SqlSessionTemplate getWriteSqlSession() {
		return writeSqlSession;
	}

	public void setWriteSqlSession(SqlSessionTemplate writeSqlSession) {
		this.writeSqlSession = writeSqlSession;
	}

	public SqlSessionTemplate getReadSqlSession() {
		return readSqlSession;
	}

	public void setReadSqlSession(SqlSessionTemplate readSqlSession) {
		this.readSqlSession = readSqlSession;
	}

	/**
	 * 获取默认的SqlSessionTemplate
	 * 
	 * @return
	 */
	public SqlSessionTemplate getSqlSession() {
		return getSqlSession(false);
	}

	public SqlSessionTemplate getSqlSession(boolean isReadOnly) {
		/*if (isReadOnly) {
			return this.getReadSqlSession();
		}*/
		return this.getWriteSqlSession();
	}


}
